home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / programming / libraries / newiff.lha / NewIFF / NewIFF39.lha / newiff39 / modules / parse.c < prev    next >
C/C++ Source or Header  |  1993-09-28  |  10KB  |  444 lines

  1. /*  
  2.  * parse.c - iffparse file IO support module
  3.  *   based on some of looki.c by Leo Schwab
  4.  *
  5.  * The filename for clipboard is -c or -cUnit as in -c0 -c1 etc. (default 0)
  6.  *
  7.  * 39.10 - fix CloseClipboard() cast to (struct ClipboardHandle *)
  8.  */
  9.  
  10. #include <exec/types.h>
  11.  
  12. #include "iffp/iff.h"
  13.  
  14. /* local function prototypes */
  15.  
  16. static LONG stdio_stream(struct Hook *, struct IFFHandle *, struct IFFStreamCmd *);
  17.  
  18. UBYTE *omodes[2] = {"r","w"};
  19.  
  20.  
  21. /* openifile
  22.  *
  23.  * Passed a ParseInfo structure with a not-in-use IFFHandle, filename
  24.  *   ("-c" or -cUnit like "-c1" for clipboard), and IFF open mode
  25.  *   (IFFF_READ or IFFF_WRITE) opens file or clipboard for use with
  26.  *   iffparse.library support modules.
  27.  *
  28.  * Returns 0 for success or an IFFERR (libraries/iffparse.h)
  29.  */
  30.  
  31. LONG openifile(struct ParseInfo *pi, UBYTE *filename, ULONG iffopenmode)
  32. {
  33.     struct IFFHandle    *iff;
  34.     BOOL    cboard;
  35.     ULONG     unit = PRIMARY_CLIP;
  36.     LONG     error;
  37.  
  38.     if(!pi)            return(CLIENT_ERROR);
  39.         if(!(iff=pi->iff))    return(CLIENT_ERROR);
  40.  
  41.     cboard = (*filename == '-'  &&  filename[1] == 'c');
  42.      if(cboard && filename[2])    unit = atoi(&filename[2]);
  43.  
  44.     if (cboard)
  45.         {
  46.         /*
  47.          * Set up IFFHandle for Clipboard I/O.
  48.          */
  49.         pi->clipboard = TRUE;
  50.         if (!(iff->iff_Stream =
  51.                 (ULONG)OpenClipboard(unit)))
  52.             {
  53.             message(SI(MSG_IFFP_NOCLIP_D),unit);
  54.             return(NOFILE);
  55.             }
  56.         InitIFFasClip(iff);
  57.         }
  58.     else
  59.         {
  60.         pi->clipboard = FALSE;
  61.         /*
  62.          * Set up IFFHandle for buffered stdio I/O.
  63.          */
  64.         if (!(iff->iff_Stream = (ULONG)
  65.            fopen(filename, omodes[iffopenmode & 1])))
  66.             {
  67.             message(SI(MSG_IFFP_NOFILE_S),filename);
  68.             return(NOFILE);
  69.             }
  70.         else initiffasstdio(iff);
  71.         }
  72.  
  73.     D(bug("%s file opened: \n", cboard ? "[Clipboard]" : (char *)filename));
  74.  
  75.     pi->filename = filename;
  76.  
  77.     error=OpenIFF(iff, iffopenmode);
  78.  
  79.     pi->opened = error ? FALSE : TRUE;    /* currently open handle */
  80.  
  81.     D(bug("OpenIFF error = %ld\n",error));
  82.     return(error);
  83. }
  84.  
  85.  
  86. /* closeifile
  87.  *
  88.  * closes file or clipboard opened with openifile, and frees all
  89.  *   iffparse context parsed by parseifile.
  90.  *
  91.  * Note - You should closeifile as soon as possible if using clipboard
  92.  *   ("-c[n]").  You also need to closeifile if, for example, you wish to
  93.  *   reopen the file to write changes back out.  See the copychunks.c
  94.  *   module for routines which allow you clone the chunks iffparse has
  95.  *   gathered so that you can closeifile and still be able to modify and
  96.  *   write back out gathered chunks.
  97.  *   
  98.  */
  99.  
  100. void closeifile(struct ParseInfo *pi)
  101. {
  102. struct IFFHandle *iff;
  103.  
  104.     D(bug("closeifile:\n"));
  105.  
  106.     if(!pi)            return;
  107.         if(!(iff=pi->iff))    return;
  108.  
  109.     DD(bug("closeifile: About to CloseIFF if open, iff=$%lx, opened=%ld\n",
  110.             iff, pi->opened));
  111.  
  112.     if(pi->opened)    CloseIFF(iff);
  113.  
  114.     DD(bug("closeifile: About to close %s, stream=$%lx\n",
  115.             pi->clipboard ? "clipboard" : "file", iff->iff_Stream));
  116.     if(iff->iff_Stream)
  117.         {
  118.         if (pi->clipboard)
  119.            CloseClipboard((struct ClipboardHandle *)(iff->iff_Stream));
  120.         else
  121.            fclose ((FILE *)(iff->iff_Stream));
  122.         }
  123.  
  124.     iff->iff_Stream = NULL;
  125.     pi->clipboard = NULL;
  126.     pi->opened = NULL;
  127. }
  128.  
  129.  
  130. /* parseifile
  131.  *
  132.  * Passed a ParseInfo with an initialized and open IFFHandle,
  133.  *  grouptype (like ID_FORM), groupid (like ID_ILBM),
  134.  *  and TAG_DONE terminated longword arrays of type,id
  135.  *  for chunks to be grabbed, gathered, and stopped on
  136.  *  (like { ID_ILBM, ID_BMHD, ID_ILBM, ID_CAMG, TAG_DONE })
  137.  *  will parse an IFF file, grabbing/gathering and stopping
  138.  *  on specified chunk.
  139.  *
  140.  * Note - you can call getcontext() (to continue after a stop chunk) or
  141.  *  nextcontext() (after IFFERR_EOC, to parse next form in the same file)
  142.  *  if you wish to continue parsing the same IFF file.  If parseifile()
  143.  *  has to delve into a complex format to find your desired FORM, the
  144.  *  pi->hunt flag will be set.  This should be a signal to you that
  145.  *  you may not have the capability to simply modify and rewrite
  146.  *  the data you have gathered.
  147.  *
  148.  * Returns 0 for success else and IFFERR (libraries/iffparse.h)
  149.  */ 
  150.  
  151. LONG parseifile(pi,groupid,grouptype,propchks,collectchks,stopchks)
  152. struct    ParseInfo *pi;
  153. LONG groupid, grouptype;
  154. LONG *propchks, *collectchks, *stopchks;
  155. {
  156. struct IFFHandle *iff;    
  157. register struct ContextNode    *cn;
  158. LONG            error = 0L;
  159.  
  160.  
  161.     D(bug("parseifile:\n")); 
  162.  
  163.         if(!(iff=pi->iff))    return(CLIENT_ERROR);
  164.  
  165.     if(!iff->iff_Stream)    return(IFFERR_READ);
  166.  
  167.     pi->hunt = FALSE;
  168.  
  169.     /*
  170.      * Declare property, collection and stop chunks.
  171.      */
  172.     if (propchks)
  173.       if (error = PropChunks (iff, propchks, chkcnt(propchks)))
  174.         return (error);
  175.     if (collectchks)
  176.       if (error =
  177.           CollectionChunks(iff, collectchks, chkcnt(collectchks)))
  178.         return (error);
  179.     if (stopchks)
  180.       if (error = StopChunks (iff, stopchks, chkcnt(stopchks)))
  181.         return (error);
  182.  
  183.     /*
  184.      * We want to stop at the end of an ILBM context.
  185.      */
  186.     if (grouptype)
  187.       if (error = StopOnExit (iff, grouptype, groupid))
  188.         return(error);
  189.  
  190.     /*
  191.      * Take first parse step to enter main chunk.
  192.      */
  193.     if (error = ParseIFF (iff, IFFPARSE_STEP))
  194.         return(error);
  195.  
  196.     /*
  197.      * Test the chunk info to see if simple form of type we want (ILBM).
  198.      */
  199.     if (!(cn = CurrentChunk (iff)))
  200.         {
  201.         /*
  202.          * This really should never happen.  If it does, it means
  203.          * our parser is broken.
  204.          */
  205.         message(SI(MSG_IFFP_NOTOP));
  206.         return(NOFILE);
  207.         }
  208.  
  209.     if (cn->cn_ID != groupid  ||  cn->cn_Type != grouptype)
  210.         {
  211.         
  212.         D(bug("This is a(n) %.4s.%.4s.  Looking for embedded %.4s's...\n",
  213.           &cn->cn_Type, &cn->cn_ID, &grouptype));
  214.  
  215.         pi->hunt = TRUE;    /* Warning - this is a complex file */
  216.         }
  217.  
  218.     if(!error)    error = getcontext(iff);
  219.     return(error);
  220. }
  221.  
  222. /* chkcnt
  223.  *
  224.  * simply counts the number of chunk pairs (type,id) in array
  225.  */
  226. LONG chkcnt(LONG *taggedarray)
  227. {
  228. LONG k = 0;
  229.  
  230.     while(taggedarray[k] != TAG_DONE) k++;
  231.     return(k>>1);
  232. }
  233.  
  234.  
  235. /* currentchunkis
  236.  *
  237.  * returns the ID of the current chunk (like ID_CAMG)
  238.  */
  239. LONG currentchunkis(struct IFFHandle *iff, LONG type, LONG id)
  240. {
  241. register struct ContextNode    *cn;
  242. LONG result = 0;
  243.  
  244.     if (cn = CurrentChunk (iff))
  245.         {
  246.         if((cn->cn_Type == type)&&(cn->cn_ID == id)) result = 1;
  247.         }
  248.     return(result);
  249. }
  250.  
  251.  
  252. /* contextis
  253.  *
  254.  * returns the enclosing context of the current chunk (like ID_ILBM)
  255.  */
  256. LONG contextis(struct IFFHandle *iff, LONG type, LONG id)
  257. {
  258. register struct ContextNode    *cn;
  259. LONG result = 0;
  260.  
  261.        if (cn = (CurrentChunk (iff)))
  262.            {
  263.            if (cn = (ParentChunk(cn)))
  264.                {
  265.                if((cn->cn_Type == type)&&(cn->cn_ID == id)) result = 1;
  266.                }
  267.        }
  268.  
  269.     D(bug("This is a %.4s %.4s\n",&cn->cn_Type,&cn->cn_ID));
  270.  
  271.     return(result);
  272. }
  273.  
  274.  
  275. /* getcontext()
  276.  *
  277.  * Continues to gather the context which was specified to parseifile(),
  278.  *  stopping at specified stop chunk, or end of context, or EOF
  279.  *
  280.  * Returns 0 (stopped on a stop chunk)
  281.  *      or IFFERR_EOC (end of context, not an error)
  282.  *      or IFFER_EOF (end of file)
  283.  */
  284. LONG getcontext(iff)
  285. struct    IFFHandle *iff;
  286. {
  287.     LONG error = 0L;
  288.  
  289.     /* Based on our parse initialization,
  290.      * ParseIFF() will return on a stop chunk (error = 0)
  291.      * or end of context for an ILBM FORM (error = IFFERR_EOC)
  292.      * or end of file (error = IFFERR_EOF)
  293.      */
  294.     return(error = ParseIFF(iff, IFFPARSE_SCAN));
  295. }
  296.  
  297.  
  298. /* nextcontext
  299.  *
  300.  * If you have finished parsing and reading your context (IFFERR_EOC),
  301.  *   nextcontext will enter the next context contained in the file
  302.  *   and parse it.
  303.  *
  304.  * Returns 0 or an IFFERR such as IFFERR_EOF (end of file)
  305.  */
  306.  
  307. LONG nextcontext(iff)
  308. struct    IFFHandle *iff;
  309. {
  310.     LONG error = 0L;
  311.  
  312.     error = ParseIFF(iff, IFFPARSE_STEP);
  313.  
  314.     D(bug("nextcontext: Got through next step\n"));
  315.  
  316.     return(error);
  317. }
  318.  
  319.  
  320. /* findpropdata
  321.  *
  322.  * finds specified chunk parsed from IFF file, and
  323.  *   returns pointer to its sp_Data (or 0 for not found)
  324.  */
  325. UBYTE *findpropdata(iff, type, id)
  326. struct IFFHandle    *iff;
  327. LONG type, id;
  328.     {
  329.     register struct StoredProperty    *sp;
  330.  
  331.     if(sp = FindProp (iff, type, id)) return(sp->sp_Data);
  332.     return(0);
  333.     }
  334.  
  335.  
  336. /*
  337.  * File I/O hook functions which the IFF library will call.
  338.  * A return of 0 indicates success (no error).
  339.  *
  340.  * Iffparse.library calls this code via struct Hook and Hook.asm
  341.  */
  342. static LONG
  343. stdio_stream (struct Hook *hook, struct IFFHandle *iff,
  344.             struct IFFStreamCmd *actionpkt)
  345. {
  346.     register FILE    *stream;
  347.     register LONG    nbytes;
  348.     register int    actual;
  349.     register UBYTE    *buf;
  350.     long    len;
  351.  
  352.     stream    = (FILE *) iff->iff_Stream;
  353.     if(!stream)    return(1);
  354.  
  355.     nbytes    = actionpkt->sc_NBytes;
  356.     buf    = (UBYTE *) actionpkt->sc_Buf;
  357.  
  358.     switch (actionpkt->sc_Command) {
  359.     case IFFSCC_READ:
  360.         do {
  361.             actual = nbytes > 32767 ? 32767 : nbytes;
  362.             if ((len=fread (buf, 1, actual, stream)) != actual)
  363.                 break;
  364.             nbytes -= actual;
  365.             buf += actual;
  366.         } while (nbytes > 0);
  367.         return (nbytes ? IFFERR_READ : 0 );
  368.  
  369.     case IFFSCC_WRITE:
  370.         do {
  371.             actual = nbytes > 32767 ? 32767 : nbytes;
  372.             if ((len=fwrite (buf, 1, actual, stream)) != actual)
  373.                 break;
  374.             nbytes -= actual;
  375.             buf += actual;
  376.         } while (nbytes > 0);
  377.         return (nbytes ? IFFERR_WRITE : 0);
  378.  
  379.     case IFFSCC_SEEK:
  380.         return ((fseek (stream, nbytes, 1) == -1) ? IFFERR_SEEK : 0);
  381.  
  382.     default:
  383.         /*  No _INIT or _CLEANUP required.  */
  384.         return (0);
  385.     }
  386. }
  387.  
  388. /* initiffasstdio (ie. init iff as stdio)
  389.  *
  390.  * sets up hook callback for the file stream handler above
  391.  */
  392. void initiffasstdio (iff)
  393. struct IFFHandle *iff;
  394. {
  395.     extern LONG        HookEntry();
  396.     static struct Hook    stdiohook = {
  397.         { NULL },
  398.         (ULONG (*)()) HookEntry,
  399.         (ULONG (*)()) stdio_stream,
  400.         NULL
  401.     };
  402.  
  403.     /*
  404.      * Initialize the IFF structure to point to the buffered I/O
  405.      * routines.  Unbuffered I/O is terribly slow.
  406.      */
  407.     InitIFF (iff, IFFF_FSEEK | IFFF_RSEEK, &stdiohook);
  408. }
  409.  
  410.  
  411. /*
  412.  * PutCk
  413.  *
  414.  * Writes one chunk of data to an iffhandle
  415.  *
  416.  */
  417. long PutCk(struct IFFHandle *iff, long id, long size, void *data)
  418.     {
  419.     long error = 0, wlen;
  420.  
  421.     D(bug("PutCk: asked to push chunk \"%.4s\" ($%lx) length %ld\n",&id,id,size));
  422.  
  423.     if(error=PushChunk(iff, 0, id, size))
  424.     {
  425.     D(bug("PutCk: PushChunk of %.4s, error = %s, size = %ld\n",
  426.         id, IFFerr(error), id));
  427.     }
  428.     else
  429.     {
  430.     D(bug("PutCk: PushChunk of %.4s, error = %ld\n",&id, error));
  431.  
  432.     /* Write the actual data */
  433.     if((wlen = WriteChunkBytes(iff,data,size)) != size)
  434.         {
  435.         D(bug("WriteChunkBytes error: size = %ld, wrote %ld\n",size,wlen));
  436.         error = IFFERR_WRITE;
  437.         }
  438.     else error = PopChunk(iff);
  439.     D(bug("PutCk: After PopChunk - error = %ld\n",error));
  440.     }
  441.     return(error);
  442.     }
  443.  
  444.